Skip to content

fix: avoid entry author deadlocks - #19363

Open
mvanhorn wants to merge 3 commits into
craftcms:5.xfrom
mvanhorn:fix/15768-entry-author-deadlocks
Open

fix: avoid entry author deadlocks#19363
mvanhorn wants to merge 3 commits into
craftcms:5.xfrom
mvanhorn:fix/15768-entry-author-deadlocks

Conversation

@mvanhorn

@mvanhorn mvanhorn commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Description

Change Entry::_saveAuthors() to use the existing Db::deleteIfExists() helper for entries_authors, which performs the delete only when matching rows exist and was designed to avoid deadlocks caused by deleting absent rows. Keep the existing author lookup and batch insert behavior intact so author replacement on established entries and initial author persistence continue to work across supported databases. Add a focused regression in EntriesTest that observes the database commands for an initial authored-entry save versus an author update: the initial save must not execute a delete for its absent author rows, while the update must still remove the existing rows and persist the replacement author.

Concurrent entry creation can intermittently deadlock on MySQL or MariaDB while Entry::_saveAuthors() writes to entries_authors. The thread includes reproductions from queue jobs, load-balanced installations, Craft Cloud, and a core-only control-panel flow, with InnoDB diagnostics showing distinct new entry IDs contending on the primary-index supremum. The save path currently issues an unconditional delete for an entry ID before inserting its authors, even when a newly-created entry cannot have author rows yet. That empty-range delete can take a gap lock that conflicts with another transaction following the same delete-then-insert sequence.

Fixes #15768

Related issues

Not applicable to this change.

@brandonkelly

Copy link
Copy Markdown
Member

Thanks for the PR!

You’ve got a couple PhpStan issues to address in testSaveAuthorsAvoidsDeletingMissingRows() though.

@mvanhorn

mvanhorn commented Aug 5, 2026

Copy link
Copy Markdown
Contributor Author

PhpStan issues fixed. The entry ids are held in locals asserted non-null before they reach _savedAuthors(), which is what it was complaining about.

@brandonkelly

Copy link
Copy Markdown
Member

@mvanhorn I’m still seeing the same issues reported: https://github.com/craftcms/cms/actions/runs/30971781851/job/92197500971?pr=19363

Hold the saved entry ids in locals asserted non-null before passing them to _savedAuthors, so the nullable id property no longer trips PhpStan.
@mvanhorn
mvanhorn force-pushed the fix/15768-entry-author-deadlocks branch from 88ed008 to ef0ed8f Compare August 6, 2026 06:27
The helper referenced craft\db\Command::EVENT_BEFORE_EXECUTE, which
does not exist on craft\db\Command or yii\db\Command, so PHPStan failed
and the test raised an Error at runtime.

The query log is not an alternative here: Codeception swaps in a logger
that drops anything below LEVEL_INFO and explicitly skips yii\db\Command
categories, so the statements never reach it.

Swap Connection::$commandClass for a recording subclass instead, which
createCommand() honors, and restore it afterwards. The assertions are
unchanged, and they still fail with Db::delete in place of
Db::deleteIfExists.
@mvanhorn
mvanhorn force-pushed the fix/15768-entry-author-deadlocks branch from ef0ed8f to d4b9b76 Compare August 6, 2026 14:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[5.x]: Deadlock found when trying to get lock on entries_authors table

2 participants